Fargateのコンテナ環境変数をSecrets Managerで保護してみた
つい先日、AWS ブログにて Fargate から Secrets Manager を利用する方法が紹介されていました。
本機能のリリース自体は、2019/4/3 にお伝えされており、詳細等については既に公式ドキュメントへ記載があります。
- AWS Fargate PV1.3 がシークレットを追加、コンテナの依存関係の管理を強化
- Specifying Sensitive Data - Amazon Elastic Container Service
Fargate & Secrets Manager の組み合わせを未だ利用したことが無かったため、AWS Secrets Manager に保存したシークレット・メッセージを AWS Fargate の Nginx コンテナで確認できるかサクッと試してみました。
やってみた
AWS Secrets Manager でシークレットを作成しないことには始まらないため、AWS CLI で作成します。
aws secretsmanager create-secret --region ap-northeast-1 \ --name SECRET_MESSAGE \ --secret-string <your secret message here>
Fargate タスクが Secrets Manager からこのシークレットを取得するためには、ECS タスク実行ロールに対して secretsmanager:GetSecretValue アクションを許可する必要があります。そこで、ECS タスク実行ロールを作成した後に IAM ポリシードキュメントを作成し、ロールと関連付けます。
まずは、ECS タスク実行ロールを作成します。
$ cat <<EOF > ecs-task-role-trust-policy.json { "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "ecs-tasks.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF $ aws iam create-role --region ap-northeast-1 \ --role-name nginx-task-execution-role \ --assume-role-policy-document \ file://ecs-task-role-trust-policy.json
次に必要な機能を定義した JSON ファイルからポリシードキュメントを作成し、ロールに関連付けます。 シークレットの ARN は、実際の値に置き換えてください。
$ cat <<EOF > nginx-iam-policy-task-execution-role.json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue" ], "Resource": [ "arn:aws:secretsmanager:ap-northeast-1:012345678912:secret:SECRET_MESSAGE" ] }, { "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "*" } ] } EOF $ aws iam put-role-policy --region ap-northeast-1 \ --role-name nginx-task-execution-role \ --policy-name nginx-iam-policy-task-execution-role \ --policy-document file://nginx-iam-policy-task-execution-role.json
次に Fargate クラスターを作成します。 シェル変数(AWS_ACCESS_KEY_ID や AWS_SECRET_ACCESS_KEY)は、予め設定しておいてください。
$ ecs-cli configure --cluster web --region ap-northeast-1 \ --default-launch-type FARGATE $ ecs-cli configure profile --access-key $AWS_ACCESS_KEY_ID \ --secret-key $AWS_SECRET_ACCESS_KEY --profile-name default $ ecs-cli up INFO[0000] Created cluster cluster=web region=ap-northeast-1 INFO[0000] Waiting for your cluster resources to be created... INFO[0001] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS INFO[0061] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS VPC created: vpc-id Subnet created: subnet-id1 Subnet created: subnet-id2 Cluster creation succeeded.
作成された VPC の ID やサブネット ID は後で利用するため記録しておいてください。 ここでは、HTTP アクセスを許可するセキュリティグループを作成します。 シェル変数(VPC_ID や SG_ID)は、設定してからコマンドを実行してください。
$ aws ec2 create-security-group --group-name "web-sg" \ --description "HTTP Only" --vpc-id $VPC_ID $ aws ec2 authorize-security-group-ingress --group-id \ $SG_ID --protocol tcp --port 80 --cidr 0.0.0.0/0
最後に、構成ファイル(docker-compose.yml,ecs-params.yml)を作成し、デプロイしましょう。
docker-compose.yml
version: '3' services: web: image: nginx ports: - "80:80" command: /bin/bash -c "echo $$SECRET_MESSAGE > /usr/share/nginx/html/index.html && exec nginx -g 'daemon off;'" logging: driver: awslogs options: awslogs-group: developers.io awslogs-region: ap-northeast-1 awslogs-stream-prefix: nginx
環境変数名(SECRET_MESSAGE)に二重のドル記号を付与することで、Compose で処理せず Secrets Manager で挿入されたコンテナの環境変数を参照することが可能になります。
You can use a $$ (double-dollar sign) when your configuration needs a literal dollar sign. This also prevents Compose from interpolating a value, so a $$ allows you to refer to environment variables that you don’t want processed by Compose.
ecs-params.yml
version: 1 task_definition: task_execution_role: arn:aws:iam::aws_account_id:role/nginx-task-execution-role ecs_network_mode: awsvpc task_size: mem_limit: 0.5GB cpu_limit: 256 services: web: secrets: - value_from: arn:aws:secretsmanager:region:aws_account_id:secret:secret_name-AbCdEf name: SECRET_MESSAGE run_params: network_configuration: awsvpc_configuration: subnets: - subnet_id - subnet_id security_groups: - security_group_id assign_public_ip: ENABLED
subnet_id や security_group_id、IAM Role やシークレットの ARN 等は、利用している環境の値に置き換えてください。ファイルを作成したら準備完了です!最後にデプロイしましょう。
$ ecs-cli compose --project-name web service up --create-log-groups --cluster-config default $ ecs-cli compose --project-name web service ps --cluster-config default Name State Ports TaskDefinition Health 55c36321-73af-47fb-be50-5bc8f2428668/web RUNNING 18.182.45.190:80->80/tcp web:10 UNKNOWN
デプロイされたコンテナ(Nginx)へブラウザから、アクセスしてみます。
AWS Secrets Manager に登録したシークレットの値を確認してみると、、、
取得できているようですね。
皆さんお気づきかもしれませんが、クラスメソッドは 2019/7/7 に創立 15周年ということで、15% OFF キャンペーンを期間限定(2019/7末まで)で開催中です。よろしければ、是非この機会にメンバーズを利用してみてはいかがでしょうか?
さいごに
以前に Serverless Framework(Lambda)で Secrets Manager を利用する方法を簡単に紹介しましたが、これからは Fargate でも Secrets Manager を活用することで、安全に開発や運用を行うことが出来るものと期待します。
なお、本記事でご紹介した手順等の詳細は、下記の公式のドキュメントを参照してください。
- チュートリアル: Amazon ECS CLI を使用して Fargate タスクのクラスターを作成する - Amazon Elastic Container Service
- Amazon ECS パラメータの使用 - Amazon Elastic Container Service
ではでは